package com.yunxin.download.server.service.impl;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.yunxin.download.server.infra.constant.FileExportConstant;
import com.yunxin.download.server.infra.constant.enums.DownloadFileStatusEnum;
import com.yunxin.download.server.infra.constant.enums.DownloadFormatEnum;
import com.yunxin.download.server.infra.repository.DownloadRecordDao;
import com.yunxin.download.server.infra.support.task.ExportAsyncTask;
import com.yunxin.download.server.infra.utils.DateUtils;
import com.yunxin.download.server.model.entity.DownloadRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.Date;
import java.util.concurrent.*;
import java.util.function.Supplier;

/**
 * @author zero°
 * @since 2023-06-15
 */
@Slf4j
public class GeneratorExportService {

    @Autowired
    private DownloadRecordDao downloadRecordDao;

    protected static final ExecutorService EXECUTOR_SERVICE;

    /**
     * 核心线程数  假设目前机器是 4c8t  io型任务
     */
    protected static final int CORE_THREAD_NUM = 9;

    /**
     * 最大线程数
     */
    protected static final int MAX_THREAD_NUM = 9;

    /**
     * 线程工作队列最大数量
     */
    protected static final int MAX_QUEUE_SIZE = 20000;

    static {
        CustomizableThreadFactory customizableThreadFactory = new CustomizableThreadFactory();
        customizableThreadFactory.setDaemon(true);
        customizableThreadFactory.setThreadNamePrefix("EXPORT_POOL");
        EXECUTOR_SERVICE = new ThreadPoolExecutor(CORE_THREAD_NUM, MAX_THREAD_NUM,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(MAX_QUEUE_SIZE),
                customizableThreadFactory, (r, executor) -> {
            //自定义抛弃任务策略  目前直接抛弃
            throw new RejectedExecutionException("导出任务提交失败，请及时处理");
        });
    }

    /**
     * 执行导出
     * @param username username
     * @param methodConfigId methodConfigId
     * @param fileName fileName
     * @param exportHandle exportHandle
     */
    protected void export(String username, Long methodConfigId, String fileName, Supplier<String> exportHandle) {

        DownloadRecord downloadRecord = this.buildDownloadRecord(username, fileName, methodConfigId);
        // 获取当前线程数据源
        String dataSourceName = DynamicDataSourceContextHolder.peek();
        // 清理掉当前线程的数据源，让默认的数据源不受影响(方便插入导出记录数据)
        DynamicDataSourceContextHolder.clear();
        downloadRecordDao.insertSelective(downloadRecord);
        //线程池 执行多线程
        ExportAsyncTask exportAsyncTask = new ExportAsyncTask(dataSourceName, exportHandle, downloadRecordDao, downloadRecord);
        EXECUTOR_SERVICE.execute(exportAsyncTask);
    }

    protected String getFileName(String fileName) {
        return fileName + DateUtils.X.getDateStr(new Date(), FileExportConstant.DATE_CUR_MIN_SECONDS);
    }

    /**
     * 生成下载记录
     * @param userName userName
     * @param fileName fileName
     * @param methodConfigId methodConfigId
     * @return DownloadRecord
     */
    private DownloadRecord buildDownloadRecord(String userName, String fileName, Long methodConfigId) {
        DownloadRecord downloadRecord = new DownloadRecord();
        downloadRecord.setDownloadFileStatus(DownloadFileStatusEnum.CREATING.getStatus());
        downloadRecord.setDownloadStatus(0);
        downloadRecord.setDownloadMethodConfigId(methodConfigId);
        downloadRecord.setDownloadTime(new Date());
        downloadRecord.setDownloadFileName(fileName);
        downloadRecord.setDownloaderName(userName);
        downloadRecord.setDownloadFileUrl("");
        downloadRecord.setOssKey("");
        downloadRecord.setDownloadFormat(DownloadFormatEnum.XLSX.getType());
        return downloadRecord;
    }

}
